#include <QtGui>
#include <string>

#include "representationDialog.h"
#include "representationPages.h"
#include "../src/data.h"
#include "../src/spatialFilter.h"

RepresentationDialog::RepresentationDialog(QWidget *_parent, QImage *_i) : QDialog(_parent), originalImage(_i){
    qDebug() << _i->format();
    if(_i->format() != QImage::Format_RGB32) testImage = new QImage(_i->convertToFormat(QImage::Format_RGB32));
    else testImage = new QImage(*_i);

    filter = new Representation(new Data(testImage->bits(), testImage->width(), testImage->height()));


    QSplitter *horizontalSplitter = new QSplitter(this);
    horizontalSplitter->setOrientation(Qt::Horizontal);
    QSplitter *verticalSplitter = new QSplitter(horizontalSplitter);
    verticalSplitter->setOrientation(Qt::Vertical);


    preview = new Image(verticalSplitter, testImage);
//    preview->setAreaSize(600, 400);

    contentsWidget = new QListWidget(horizontalSplitter);
//    contentsWidget->setViewMode(QListView::IconMode);
//    contentsWidget->setIconSize(QSize(50, 31));
//    contentsWidget->setMovement(QListView::Adjust);
    contentsWidget->setResizeMode(QListView::Adjust);
    contentsWidget->setMinimumWidth(200);
    contentsWidget->setMaximumWidth(300);
    contentsWidget->setSpacing(7);



    /*INCLUINDO AS PAGINAS*/
    pagesWidget = new QStackedWidget(verticalSplitter);

    BoundaryFollowingPage *bfp = new BoundaryFollowingPage;
    pagesWidget->addWidget(bfp);
    connect(bfp, SIGNAL(done()), this, SLOT(boundaryFollowingRepresentation()));

    ChainCodePage *ccp = new ChainCodePage;
    pagesWidget->addWidget(ccp);
    connect(ccp, SIGNAL(done()), this, SLOT(chainCodeRepresentation()));

    SplittingPage *sp = new SplittingPage;
    pagesWidget->addWidget(sp);
    connect(sp, SIGNAL(done()), this, SLOT(splittingRepresentation()));

    pagesWidget->addWidget(new BasicDescriptorsPage);
    pagesWidget->addWidget(new MomentInvariantsDescriptorsPage);
    pagesWidget->addWidget(new HistogramDescriptorsPage);



    QPushButton *closeButton = new QPushButton(tr("Fechar"));
    QPushButton *applyButton = new QPushButton(tr("Aplicar"));

    connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
    connect(applyButton, SIGNAL(clicked()), this, SLOT(apply()));

    createIcons();
    contentsWidget->setCurrentRow(0);


    verticalSplitter->addWidget(preview);
    verticalSplitter->addWidget(pagesWidget);
    horizontalSplitter->addWidget(contentsWidget);
    horizontalSplitter->addWidget(verticalSplitter);

    resize(600, 500);

    QHBoxLayout *buttonsLayout = new QHBoxLayout;
    buttonsLayout->addStretch(1);
    buttonsLayout->addWidget(applyButton);
    buttonsLayout->addWidget(closeButton);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(horizontalSplitter);
    mainLayout->addLayout(buttonsLayout);
    setLayout(mainLayout);

    setWindowTitle(QString::fromUtf8("Galeria de Representações e Descritores"));
}

RepresentationDialog::~RepresentationDialog(){
}

void RepresentationDialog::createIcons(){
    addButton(new QListWidgetItem(contentsWidget), "images/sem_ico.png", QString::fromUtf8(BOUNDARY_FOLLOWING));
    addButton(new QListWidgetItem(contentsWidget), "images/sem_ico.png", QString::fromUtf8(CHAIN_CODE));
    addButton(new QListWidgetItem(contentsWidget), "images/sem_ico.png", QString::fromUtf8(SPLITTING));
    addButton(new QListWidgetItem(contentsWidget), "images/sem_ico.png", QString::fromUtf8(BASIC_DESCRIPTORS));
    addButton(new QListWidgetItem(contentsWidget), "images/sem_ico.png", QString::fromUtf8(MOMENT_INVARIANTS));
    addButton(new QListWidgetItem(contentsWidget), "images/sem_ico.png", QString::fromUtf8(HISTOGRAM_DESCRIPTOR));

    connect(contentsWidget, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
        this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*)));
}

void RepresentationDialog::addButton(QListWidgetItem *_button, QString _ico, QString _name){
//    _button->setIcon(QIcon(_ico));
    _button->setText(_name);
    _button->setTextAlignment(Qt::AlignLeft | Qt::AlignBottom);
    _button->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
}

void RepresentationDialog::apply(){
//    if(originalImage) delete originalImage;

    emit done(new QImage(*testImage));
    emit done();
    accept();
}

void RepresentationDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous){
    if (!current)
        current = previous;

    pagesWidget->setCurrentIndex(contentsWidget->row(current));

//    bool b = ((Representation*)filter)->isBlackWhite();
//    if(!b){
//        /*lembrar de trocar isso *******/
//        QMessageBox::StandardButton reply;
//        reply = QMessageBox::information(this, tr("Erro!"), QString::fromUtf8("A imagem não está somente com preto e branco."));
//
//        return;
//    }

    revert();

    if(current->text() == QString::fromUtf8(BOUNDARY_FOLLOWING)){
//        std::cout << "mudando para boundary following" << std::endl;

        SpatialFilter sf(new Data(testImage->bits(), testImage->width(), testImage->height()));
        sf.thresholdingFilter(127);


        pagesWidget->show();
    }else if(current->text() == QString::fromUtf8(CHAIN_CODE)){
//        std::cout << "mudando para chain code" << std::endl;

        SpatialFilter sf(new Data(testImage->bits(), testImage->width(), testImage->height()));
        sf.thresholdingFilter(127);

        pagesWidget->show();
    }else if(current->text() == QString::fromUtf8(SPLITTING)){
//        std::cout << "mudando para solitting" << std::endl;


        SpatialFilter sf(new Data(testImage->bits(), testImage->width(), testImage->height()));
        sf.thresholdingFilter(127);

        pagesWidget->show();
    }else if(current->text() == QString::fromUtf8(BASIC_DESCRIPTORS)){
//        std::cout << "mudando para basic descr" << std::endl;

        SpatialFilter sf(new Data(testImage->bits(), testImage->width(), testImage->height()));
        sf.thresholdingFilter(127);

        pagesWidget->show();

        std::string perimeter;
        std::string area;
        std::string diameter;
        std::string compactness;
        std::string circularRatio;

        ((Representation*)filter)->basicDescriptors(&perimeter, &area, &diameter, &compactness, &circularRatio);
        BasicDescriptorsPage *bdp = (BasicDescriptorsPage *)pagesWidget->currentWidget();
        bdp->setStrings(QString(perimeter.c_str()), QString(area.c_str()), QString(diameter.c_str()), QString(compactness.c_str()), QString(circularRatio.c_str()));
    }else if(current->text() == QString::fromUtf8(MOMENT_INVARIANTS)){
        pagesWidget->show();
//        std::cout << "mudando para moment invariant" << std::endl;

        std::string m1;
        std::string m2;
        std::string m3;
        std::string m4;
        std::string m5;
        std::string m6;
        std::string m7;

        ((Representation*)filter)->momentInvariantsDescriptors(&m1, &m2, &m3, &m4, &m5, &m6, &m7);
        MomentInvariantsDescriptorsPage *mip = (MomentInvariantsDescriptorsPage *)pagesWidget->currentWidget();
        mip->setStrings(QString(m1.c_str()), QString(m2.c_str()), QString(m3.c_str()), QString(m4.c_str()), QString(m5.c_str()), QString(m6.c_str()), QString(m7.c_str()));
    }else if(current->text() == QString::fromUtf8(HISTOGRAM_DESCRIPTOR)){
        pagesWidget->show();

//        std::cout << "mudando para histogram" << std::endl;

        std::string m1;
        std::string m2;
        std::string m3;
        std::string m4;
        std::string m5;
        std::string m6;

        ((Representation*)filter)->histogramDescriptors(&m1, &m2, &m3, &m4, &m5, &m6);
        HistogramDescriptorsPage *hdp = (HistogramDescriptorsPage*)pagesWidget->currentWidget();
        hdp->setStrings(QString(m1.c_str()), QString(m2.c_str()), QString(m3.c_str()), QString(m4.c_str()), QString(m5.c_str()), QString(m6.c_str()));
    }else{

        std::cout << "ACHOU NADA!" << std::endl;
    }

//    pagesWidget->show();

    update();
//        std::cout << "updeitou" << std::endl;

}

void RepresentationDialog::update(){
    preview->update(testImage);
}

void RepresentationDialog::revert(){
    delete testImage;
    testImage = new QImage(*originalImage);
    filter->getData()->setAll(testImage->bits(), testImage->width(), testImage->height());
}

void RepresentationDialog::changeFilter(QString _filter){
    for(int i = 0; i < contentsWidget->count(); i++){
        if(contentsWidget->item(i)->text() == _filter){
            contentsWidget->setCurrentRow(i);
            return;
        }
    }
}

void RepresentationDialog::boundaryFollowingRepresentation(){
    revert();

    BoundaryFollowingPage *bfp = (BoundaryFollowingPage *)pagesWidget->currentWidget();
    Data *d = ((Representation*)filter)->boundaryFollowing();
    delete testImage;
    testImage = new QImage(d->getData(), d->getWidth(), d->getHeight(), d->getWidth()*4, testImage->format());
    update();

    bfp->tryItAgain();
}

void RepresentationDialog::chainCodeRepresentation(){
    revert();

    ChainCodePage *ccp = (ChainCodePage *)pagesWidget->currentWidget();
    int resampling = ccp->getResample();
    int xPad = resampling + resampling - (testImage->width() % resampling);
    int yPad = resampling + resampling - (testImage->height() % resampling);


    Data *testImageDataPadded = filter->padding(xPad, yPad);


//    Color c;
//    for(int i = 0; i < testImageDataPadded->getWidth(); i++){
//        for(int j = 0; j < testImageDataPadded->getHeight(); j++){
//            c = testImageDataPadded->getData(i, j);
//            if((int)c.red == 255) std::cout << " 1";
//            else if((int)c.red == 0) std::cout << " 0";
//            else  std::cout << (int)c.red ;
//        }
//         std::cout <<std::endl;
//    }



    testImage = new QImage(testImageDataPadded->getData(), testImageDataPadded->getWidth(), testImageDataPadded->getHeight(), testImageDataPadded->getWidth()*4, testImage->format());
    QImage smallTestImage = testImage->scaled((int)(testImage->width() / resampling), (int)(testImage->height() / resampling), Qt::KeepAspectRatio);
    filter->getData()->setAll(smallTestImage.bits(), smallTestImage.width(), smallTestImage.height());

    std::string chainCode = "", firstDifference = "", shapeNumber = "";
    Data *d = ((Representation*)filter)->chainCode(1, &chainCode, &firstDifference, &shapeNumber);
    delete testImage;
    testImage = new QImage(d->getData(), d->getWidth(), d->getHeight(), d->getWidth()*4, testImage->format());
    ccp->setStrings(QString(chainCode.c_str()), QString(firstDifference.c_str()), QString(shapeNumber.c_str()));

    update();

    ccp->tryItAgain();
}

void RepresentationDialog::splittingRepresentation(){
    revert();

    std::string points = "";

    std::cout << "começando o algoritmo" << std::endl;
    SplittingPage *sp = (SplittingPage *)pagesWidget->currentWidget();
    std::vector<Point> pointsVector = ((Representation*)filter)->splitting(sp->getDepth(), &points);
    sp->setPoints(QString(points.c_str()));
    std::cout << "saiu do algoritmo" << std::endl;

    Point p1, p2;
    testImage = new QImage(testImage->width(), testImage->height(), testImage->format());
    QPainter *painter = new QPainter;
    painter->begin(testImage);
    painter->setPen(QPen (Qt::white));
    //desenhar de acrodo com os pontos
    for(unsigned int i = 0; i < pointsVector.size() - 1; i++){
        p1 = pointsVector.at(i);
        p2 = pointsVector.at(i + 1);
        painter->drawLine(p1.x - 3, p1.y - 3, p2.x - 3, p2.y - 3);
        //desenhar uma reta para o atual e o proximo
    }
    p1 = pointsVector.at(0);
    painter->drawLine(p2.x - 3, p2.y - 3, p1.x - 3, p1.y - 3);
    painter->end();


    update();

    sp->tryItAgain();
}
